/*
    SEL - Simple DirectMedia Layer Extension Library
    Copyright (C) 2001 Matej Knopp <knopp@users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __sel_joystick_h__
#define __sel_joystick_h__

#include "sdl.h"

namespace SEL
{

//! Class intented to determine the abilities, and state of a joystick.
/*!
  An instance of this class represents a joystick connected to the 
  computer. In order to use this class SEL::init must have been called
  with the INIT_JOYSTICK flag. This causes SDL to scan the system
  for joysticks, and load appropriate drivers.
 */
class Joystick
{
public:
	//! Open a joystick for use.
	/*!
	  If the specified joystick couldn't be opened, an exception is thrown.
	  Devices are numbered starting with 0. 
	  
	  \param device_index  the index of the Joystick you want to open.
	 */
	Joystick (int device_index);
	
	//! Delete the joystick object instance, and close the joystick handle.
	~Joystick ();

	//! Reopen a new joystick, and optionally close the last handle.
	/*!
	  \warning Use this function carefully because you can lose the 
	  previous handle and not be able to use the joystick.
	  \param device_index the index of the joystick you want to open. 
	  \param close_last whether you want to close the last handle.
	  	  	    It's recommended to do so. Set this to false only
			    if you know, what you are doing.
	*/
	void open (int device_index, bool close_last = true);
	
	//! Close the joystick, and free the handle.
	/*!
	  \warning This function is not recommended to use. But if you
	  do so, make sure that you don't use the object instance after 
	  closing it, because it may lead to a crash.
	 */
	void close ();

	//! Return the wrapped SDL::Joystick structure.
	SDL::Joystick *joystick () 		{ return m_joystick; }

	//! Return the wrapped constant SDL::Joystick structure.
	const SDL::Joystick *joystick () const	{ return m_joystick; }


	//! Get the device index of an opened joystick.
	int index () const;
	
	//! Get the number of axis controls on an joystick.
	int numAxes () const;
	
	//! Get the number of trackballs on a joystick
	/*!
	  \note Joystick trackballs have only relative motion
	  events associated with them an their state can't be polled.
	 */
	int numBalls () const;
	
	//! Get the number of POV hats on a joystick.
	int numHats () const;
	
	//! Get the number of buttons on a joystick.
	int numButtons () const;
	
	//! Return the name of current joystick or NULL if none.
	const char *name () const;
	
	//! Get the current state of an axis control on a joystick.
	/*!
	  \return a value ranging from -32768 to 32767.
	  The \a axis indices start at index 0.
	  \param axis the index of axis control on a joystick.
	 */
	Sint16 axis (int axis);
	
	//! Get the current state of a POV hat on a joystick.
	/*!
	  The return value is one of the following positions:
	  - SDL::HAT_CENTERED
	  - SDL::HAT_UP
	  - SDL::HAT_RIGHT
	  - SDL::HAT_DOWN 
	  - SDL::HAT_LEFT
	  - SDL::HAT_RIGHTUP
	  - SDL::HAT_RIGHTDOWN
	  - SDL::HAT_LEFTUP
	  - SDL::HAT_LEFTDOWN
	  
	  The \a hat indices start at index 0.
	  \return The current hat state as mention above.
	  \param hat the index of hat control on a joystick.
	 */
	Uint8 hat (int hat);
	
	//! Get the ball axis change since the last poll.
	/*!
	  Ball indices start at index 0.
	  \return true, or false if you passed it invalid parameters.
	  
	  \param ball the index of the ball.
	  \param dx, dy the numbers where the axis changes are stored.
	 */
	bool ball (int ball, int &dx, int &dy);
	
	//! Get the state of a button on a joystick.
	/*!
	  The \a buton indices start at index 0.
	  \return The state of given \a button.
	  \param button the index of a button on a joystick.
	 */
	Uint8 button (int button) const;
	
	//! Update the current state of the open joysticks.
	/*!
	  \note This is called automatically by the event loop if
	  any joystick events are enabled.
	 */
	static void update ();
	
	//! Enable or disable joystick event polling.
	/*!
	  If joystick events are disabled, you must call Joystick::update ()
	  yourself, and check the state of the joystick when you want 
	  joystick information.
	  The \a state can be one of SDL::QUERY, SDL::ENABLE or SDL::IGNORE.
	  \param state - the state as described above.
	  \return the current state of event polling.
	 */ 
	static int eventState (int state);
	
	//! Get the number of joysticks attached to the system.
	static int count ();
	
	//! Get the implementation dependent name of a joystick.
	/*!
	  This can be called before any joysticks are opened.
	  \return the name of joystick with index \a device_index or
	    NULL, if no name can be found.
	  \param device_index the index of the queried joystick.
	 */
	static const char *name (int device_index);
	
	//! Query whether a joystick have been opened.
	/*!
	 \return true if the joystick with index \a device_index
	  have been opened or false if not.
	 \param device_index the index of the queried joystick.
	 */
	static bool opened (int device_index);

protected:
	//! The joystick structure used to identify an SDL joystick;
	SDL::Joystick *m_joystick;
};

//////////////////////////////////////////////////////////////////
//////////////////////// INLINE FUNCTIONS ////////////////////////
//////////////////////////////////////////////////////////////////

inline
Joystick::Joystick (int device_index)
{
	open (device_index);
}

inline	
Joystick::~Joystick ()
{
	m_joystick = NULL;
	close ();
}

inline void
Joystick::close ()
{
	if (m_joystick)
		SDL::JoystickClose (m_joystick);
	m_joystick = NULL;
}

inline int 
Joystick::index () const
{
	return SDL::JoystickIndex (m_joystick);
}
	
inline int 
Joystick::numAxes () const
{
	return SDL::JoystickNumAxes (m_joystick);
}

inline int 
Joystick::numBalls () const
{
	return SDL::JoystickNumBalls (m_joystick);
}
	
inline int 
Joystick::numHats () const
{
	return SDL::JoystickNumHats (m_joystick);
}
	
inline int 
Joystick::numButtons () const
{
	return SDL::JoystickNumButtons (m_joystick);
}
	
inline const char *
Joystick::name () const
{
	return SDL::JoystickName (index ());
}

inline Sint16 
Joystick::axis (int axis)
{
	return SDL::JoystickGetAxis (m_joystick, axis);
}
	
inline Uint8 
Joystick::hat (int hat)
{
	return SDL::JoystickGetHat (m_joystick, hat);
}
	
inline bool
Joystick::ball (int ball, int &dx, int &dy)
{
	return SDL::JoystickGetBall (m_joystick, ball, &dx, &dy) == 0;
}
	
inline Uint8 
Joystick::button (int button) const
{
	return SDL::JoystickGetButton (m_joystick, button);
}
	
inline void 
Joystick::update ()
{
	SDL::JoystickUpdate ();
}
	
inline int 
Joystick::eventState (int state)
{
	return SDL::JoystickEventState (state);
}
	
inline int 
Joystick::count ()
{
	return SDL::NumJoysticks ();
}
	
inline const char *
Joystick::name (int device_index)
{
	return SDL::JoystickName (device_index);
}
	
inline bool 
Joystick::opened (int device_index)
{
	return SDL::JoystickOpened (device_index);
}

} // namespace SEL;

#endif // __sel_joystick_h__
